
#import "GameManager.h"
#import "Box2dWrapper.h"
#import "BlueBird.h"
#import "YellowBird.h"

int W=480;
int H=320;

@implementation GameManager

#pragma mark ============================= Init Methods ================================

+ (GameManager*) getInstance  {
    
    static GameManager* gameManager;
		
	if (!gameManager) {
        gameManager = [[GameManager alloc] init];
        NSLog(@"gameManager Singleton angelegt!");
		[gameManager preloader];            
	}
	    
    return gameManager;
}

- (void) preloader {
    sprites = [[NSMutableArray alloc] initWithCapacity:20];
    newSprites = [[NSMutableArray alloc] initWithCapacity:20];
    destroyableSprites = [[NSMutableArray alloc] initWithCapacity:20];
   
    //Preload OGL-Textures       
    [self getTex: @"background.png" isImage: YES];
    [self getTex: @"block32x32.png" isImage: YES];
    [self getTex: @"block16x16.png" isImage: YES];
    [self getTex: @"block64x16.png" isImage: YES];
    [self getTex: @"blueBird.png" isImage: YES];
    [self getTex: @"yellowBird.png" isImage: YES];
    [self getTex: @"targetLine.png" isImage: YES];    
    
    [Box2dWrapper getInstance]; //init box2d   
     
    [[Box2dWrapper getInstance] createStaticBody: CGRectMake(-100, H+1, W+200, 1)]; 
    
    [self setOGLProjection];
    
    state = LOAD_GAME;
}

- (void) loadGame { 
    [sprites removeAllObjects];
    [newSprites removeAllObjects];
    [destroyableSprites removeAllObjects];     
    
    //Level setup
    level = [[Level alloc] init];
    [level setLevel];
    [level release];
    
    targetLineX = W-75;
}

- (void) addB2Sprite: (int) type at: (CGPoint) p {
    if (type == CUBE16x16) {
        SpriteB2 *sprite = [[SpriteB2 alloc] initWithPic: @"block16x16.png"
                                                frameCnt: 1                                     
                                               frameStep: 0
                                                   speed: CGPointMake(0, 0)
                                                     pos: p];     
        [newSprites addObject: sprite];
        [sprite release]; 
    } else if (type == CUBE32x32) {
        SpriteB2 *sprite = [[SpriteB2 alloc] initWithPic: @"block32x32.png"
                                                frameCnt: 1                                     
                                               frameStep: 0
                                                   speed: CGPointMake(0, 0)
                                                     pos: p];     
        [newSprites addObject: sprite];
        [sprite release];    
    } else if (type == CUBE64x16) {
        SpriteB2 *sprite = [[SpriteB2 alloc] initWithPic: @"block64x16.png"
                                                frameCnt: 1                                     
                                               frameStep: 0
                                                   speed: CGPointMake(0, 0)
                                                     pos: p];     
        [newSprites addObject: sprite];
        [sprite release];     
    } else if (type == BLUEBIRD) {
        BlueBird *sprite = [[BlueBird alloc] initWithPic: @"blueBird.png"
                                                frameCnt: 2                                     
                                               frameStep: 0
                                                   speed: CGPointMake(0, 0)
                                                     pos: p];     
        [newSprites addObject: sprite];
        [sprite release];    
    } else if (type == YELLOWBIRD) {
        YellowBird *sprite = [[YellowBird alloc] initWithPic: @"yellowBird.png"
                                                frameCnt: 2                                     
                                               frameStep: 0
                                                   speed: CGPointMake(0, 0)
                                                     pos: p];     
        [newSprites addObject: sprite];
        [sprite release];   
    } else {
        NSLog(@"ERROR: Unkown sprite type: %i", type); 
    } 
}

#pragma mark ============================= Game Handler ===============================

- (void) touchBegan: (CGPoint) p {    
    [self handleStates];
    if (state == PLAY_GAME) {
        for (Sprite *sprite in sprites) { 
            if ([sprite isActive]) {             
                if ([sprite getType] == BLUEBIRD) {
                    [(BlueBird *) sprite touchBegan: p];
                } 
            }   
        } 
    }      
}

- (void) touchMoved: (CGPoint) p {  
}

- (void) touchEnded: (CGPoint) p {
    if (state == PLAY_GAME) {
        for (Sprite *sprite in sprites) { 
            if ([sprite isActive]) {             
                if ([sprite getType] == BLUEBIRD) {
                    [(BlueBird *) sprite touchEnded: p];
                } 
            }   
        } 
    }  
    
    if (p.x > W-130 && p.y < 30) {
        state = LOAD_GAME;
    }
}

- (void) handleStates {   
    if (state == START_GAME) {
        state = PLAY_GAME;
    }
    else if (state == GAME_WON) {
        state = LOAD_GAME;
    }
}

- (void) drawStatesWithFrame: (CGRect) frame { 
    switch (state) {
        case LOAD_GAME: 
            [self loadGame];
            state = START_GAME;
            break;
        case START_GAME:             
            [self drawOGLString: @"Tap screen to start!" at: CGPointMake(10, 0)];
            [self drawOGLString: @"Flick/Swipe the blue birds" at: CGPointMake(10, 25)];
            [self drawOGLString: @"to free the yellow birds!" at: CGPointMake(10, 50)];
            [self drawOGLString: @"All yellow birds must pass the lantern!" at: CGPointMake(10, 100)];
            break;    
        case PLAY_GAME:
            [self playGame];
            break;
        case GAME_WON:
            [self playGame];
            [self drawOGLString: @"CONGRATULATIONS!" at: CGPointMake(W/2-100, H/2-30)];
            break;             
        default: NSLog(@"ERROR: Unkown state: %i", state);
            break;
    }    
}	 

- (void) playGame {
    timer++;    
   
    [self drawOGLImg: @"background.png" at: CGPointMake(0, 0)];
    [self drawOGLString: @"[RESTART]" at: CGPointMake(W-130, 0)];
    
    [self manageSprites];             
    [self renderSprites];  

    [[Box2dWrapper getInstance] update];     
    
    //Siegbedingung
    [self drawOGLImg: @"targetLine.png" at: CGPointMake(targetLineX-8, H-128)];   
    bool gameWon = true;
    for (Sprite *sprite in sprites) { 
        if ([sprite getType] == YELLOWBIRD) {             
            if ([sprite getPos].x < targetLineX) {
                gameWon = false;
            }              
        }
    }
    if (gameWon) {
        state = GAME_WON;
    } 
} 

- (void) checkSprite: (Sprite *) sprite {
    if ([sprite getType] == YELLOWBIRD) {                
        CGPoint pos = [sprite getPos];
        if ([sprite getPos].x >= targetLineX) {            
            [(YellowBird *) sprite twinkle];
            [self drawOGLString: @"Yippie!" at: CGPointMake(pos.x-20, pos.y-25)]; 
        } 
    }  
}

#pragma mark ============================= OGL Methods ===============================

- (void) setOGLProjection {
    //Set View
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity();    
    glOrthof(0, W, H, 0, 0, 1); 
    
    glMatrixMode(GL_MODELVIEW);
    glEnableClientState(GL_VERTEX_ARRAY); 
    glDisable(GL_DEPTH_TEST); //2D only
} 

- (void) drawOGLLineFrom: (CGPoint) p1 to: (CGPoint) p2 {
    GLshort vertices[ ] = { 
        p1.x, p1.y,
        p2.x, p2.y        
    };      

    glVertexPointer(2, GL_SHORT, 0, vertices);           
    glColor4f(1, 1, 0, 1);
    glDrawArrays(GL_LINES, 0, 2);       
}

- (void) drawOGLRect: (CGRect) rect {    
    GLshort vertices[ ] = {
        0,                  rect.size.height, 
        rect.size.width,    rect.size.height, 
        0,                  0, 
        rect.size.width,    0  
    };
        
    glVertexPointer(2, GL_SHORT, 0, vertices);           
    glColor4f(1, 1, 0, 1);
    
    glPushMatrix();      
    glTranslatef(rect.origin.x, rect.origin.y, 0);          
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 
    glPopMatrix();      
}

- (void) drawOGLImg: (NSString*) picName at: (CGPoint) p {    
    Tex *tex = [self getTex: picName isImage: YES]; 
    if (tex) {
        [tex drawAt: p];
    }
}

- (CGSize) getOGLImgDimension: (NSString*) picName {    
    Tex *tex = [self getTex: picName isImage: YES]; 
    if (tex) {
        return CGSizeMake([tex getWidth], [tex getHeight]);
    }
    return CGSizeMake(0, 0); 
}

- (void) drawOGLString: (NSString*) text at: (CGPoint) p {    
    Tex *tex = [self getTex: text isImage: NO]; 
    if (tex) {
        [tex drawAt: p];
    }
}

- (Tex *) getTex: (NSString*) name isImage: (bool) imgFlag { 
	Tex *tex = [[self getDictionary] objectForKey: name];
	if (!tex) {
		tex = [[Tex alloc] init];
        if (imgFlag) {            
            [tex createTexFromImage: name];             
        } else {
            [tex createTexFromString: name];
        }    
        [[self getDictionary] setObject: tex forKey: name];
        [tex release];         
	}          
	return tex;  
}

#pragma mark ============================= Helper Methods ===============================

- (void) setState: (int) stt {
    state = stt;
}

- (void) manageSprites {
    //NSLog(@"Sprites: %i destroyable: %i new: %i", [sprites count], [destroyableSprites count], [newSprites count]);
    
    //Cleanup 
    for (Sprite *destroyableSprite in destroyableSprites) { 
        for (Sprite *sprite in sprites) { 
            if (destroyableSprite == sprite) { 
                [sprites removeObject: sprite];
                break;
            }
        }   
    }  
    
    for (Sprite *newSprite in newSprites){ 
        [sprites addObject: newSprite];   
    } 
    
    [destroyableSprites removeAllObjects]; 
    [newSprites removeAllObjects];
}

- (void) renderSprites {
    for (Sprite *sprite in sprites) { 
        if ([sprite isActive]) {             
            [self checkSprite: sprite];
            [sprite draw];                 
        } else {
            [destroyableSprites addObject: sprite]; 
        }    
    }                
}

- (NSMutableDictionary *) getDictionary {
	if (!dictionary) { 
		dictionary = [[NSMutableDictionary alloc] init]; 
	}
	return dictionary;
}

- (void) removeFromDictionary: (NSString*) name {
    [[self getDictionary] removeObjectForKey: name];
} 

- (int) getRndBetween: (int) bottom and: (int) top {		
	int rnd = bottom + (arc4random() % (top+1-bottom)); 
	return rnd;
} 

- (void) dealloc {        
    [sprites release];
    [newSprites release];
    [destroyableSprites release];
    [dictionary release]; 
    [super dealloc];
}

@end
